參考
參考-1
基本介紹
在 C 語言中有一些 Extensions 的方法
要使用這些 Extensions 功能你可以先檢查 GNUC 是否有開
這些 Extensions 不是標準 C 的功能,是需要編譯器支援的
1 2 3 4 5
| #if __GNUC__ /* 有定義 __GNUC__ 才可以使用 Extensions */ #endif
|
如果在 GCC 編譯時加上 -pedantic
而且你有用 Extensions 的話會發出警告
也就是說當你加上 -pedantic
代表你不想要用 Extensions
Statement Exprs
將語法包在 ({})
之中,會回傳最後一段的值
如下例子總共有 4 行程式碼,但最後會回傳z
的值
1 2 3 4 5 6 7 8 9 10
| #define EXPRS ({ int x = 5; int y=10; int z=0; \ if (x > y) z = x; \ else z = y; \ z; })
int main(void) { printf("%d \n",EXPRS); return 0; }
|
Locally Declared Labels
定義一個 label 常和 goto 搭配
以下是在 while loop 裡面跳出到 labelA
記得被跳的 labelA 的後面要寫 :
1 2 3 4 5 6 7 8 9 10 11 12 13
| int main(void) { __label__ labelA; int i = 0; while(1) { goto labelA; }
labelA: printf("Fineish! \n"); return 0; }
|
Labels as Values
將 Labels 當作變數來使用
在 Labels 前使用 && 可以取得 Labels 位置
使用 goto 就可以跳到 Labels
GCC 建議使用 switch 而不是用 Labels array
除非當 switch 做不到時才考慮用 Labels array 取代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| /* Ex1 只會顯示 L1 */ int main(void) { const void *jmpLabel = &&L1; goto *jmpLabel;
printf("Hello\n");
L1: printf("L1\n"); return 0; }
/* Ex2 只會顯示 L2 (類似 switch)*/ int main(void) { const void *jmpLabel[] = {&&L1,&&L2,&&L3}; goto *jmpLabel[1];
L1: printf("L1\n"); return 0; L2: printf("L2\n"); return 0; L3: printf("L3\n"); return 0;
return 0; }
/* Ex3 改寫上述寫法,此寫法在做 shared LIB 時比較好 */ int main(void) { static const int jmpLabel[] = {&&L1-&&L1, &&L2-&&L1, &&L3-&&L1}; goto *(&&L1 + jmpLabel[0]);
L1: printf("L1\n"); return 0; L2: printf("L2\n"); return 0; L3: printf("L3\n"); return 0; return 0; }
|
Nested Functions
巢狀函示,在函式中定義另一個函式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int funcA(int a, int b) { // Nested Functions int square(int c){ return (c * c); }
return square (a) + square (b); }
int main(void) { printf("%d\n",funcA(2,3)); // 13 return 0; }
|
Typeof
回傳參數型態,如下例子typeof(a)
等於取a
型態
所以等於 int y;
1 2 3 4 5 6 7 8 9 10 11 12
| int main(void) { int a = 0; typeof(a) y; return 0; }
// 比大小的例子 #define max(a,b) ({ typeof (a) _a = (a); typeof (b) _b = (b); _a > _b ? _a : _b; })
// 或是寫成 #define max(a,b) ({ __auto_type _a = (a); __auto_type _b = (b); _a > _b ? _a : _b; })
|
Conditionals
你可以把
改寫為
當你 x 很長的時候比較有用,就不需要寫兩次 x 敘述
128-bit Integers
需要看你的硬體是否有支援
1 2 3 4 5 6
| int main(void) { __int128 a; // signed 128-bit integer unsigned __int128 b; // unsigned 128-bit integer return 0; }
|
Double-Word Integers
64 bit 長度型別
1 2 3 4 5 6
| int main(void) { long long int a; unsigned long long int b; return 0; }
|
Complex Numbers
數學的複數運算,記得要include <complex.h>
使用複數時要加上i
或j
,例如%.2fi
或%.2fj
creal()
和 cimag()
可替換為 __real__
和 __imag__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <complex.h>
int main(void) { double complex z1 = 10.0 + 5.0 * I; double complex z2 = 10.0 - 3.0 * I; printf("z1 = %.2f + %.2fi \n", creal(z1), cimag(z1)); printf("z2 = %.2f + %.2fi \n", creal(z2), cimag(z2));
double complex sum = z1 + z2; printf("Sum: z1 + z2 = %.2f %+.2fi\n", creal(sum), cimag(sum));
double complex difference = z1 - z2; printf("The difference: Z1 - Z2 = %.2f %+.2fi\n", creal(difference), cimag(difference));
double complex product = z1 * z2; printf("The product: Z1 x Z2 = %.2f %+.2fi\n", creal(product), cimag(product));
double complex quotient = z1 / z2; printf("The quotient: Z1 / Z2 = %.2f %+.2fi\n", creal(quotient), cimag(quotient));
double complex conjugate = conj(z1); printf("The conjugate of Z1 = %.2f %+.2fi\n", creal(conjugate), cimag(conjugate)); return 0; }
|
Arrays of Length Zero
此用法在於可以宣告動態大小的 struct,先看傳統用法
1 2 3 4
| typedef struct{ int age; char name[10]; }stPerson;
|
此 struct 大小就是固定 4 byte + 10 byte
如果用以下寫法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| typedef struct{ int age; char name[0]; }stPerson;
int main(void) { // 在配置記憶體時額外加上需要的大小,此例子為 20 // 你也可以改為其他大小,藉此達到改變 struct 的 size char nameLen = 20; stPerson *pPerson = malloc( sizeof(stPerson) + nameLen);
// Assign pPerson->age = 28; strncpy(pPerson->name, "Jason", strlen("Jason") + 1); printf("Age = %d\n",pPerson->age); // 28 printf("Name = %s\n",pPerson->name); // Jason // 這樣就可以利用 name array 存取自行配置的空間 printf("Name[0] = %c\n",pPerson->name[0]); // J printf("Name[1] = %c\n",pPerson->name[1]); // a printf("Name[2] = %c\n",pPerson->name[2]); // s }
|
額外參考
Macros with a Variable Number of Arguments.
Macros 使用 ...
表示可傳入多個參數
1 2 3 4 5 6 7
| #define debug(format, ...) fprintf (stderr, format, __VA_ARGS__) int main(void) { debug("%s \n","Hello"); // 1 個參數 debug("%s %s\n","Hello","World"); // 2 個參數 return 0; }
|
可以改寫為
1
| #define debug(format, args...) fprintf (stderr, format, args)
|
但以上寫法遇到沒有參數時會有問題,例如
1 2 3 4 5 6
| #define debug(format, ...) fprintf (stderr, format, __VA_ARGS__) int main(void) { debug("Hi\n"); return 0; }
|
所以可以加上 ##
來解決
1
| #define debug(format, ...) fprintf (stderr, format, ## __VA_ARGS__)
|
##
的其他用法
1 2 3 4 5 6 7 8 9 10 11
| #define sayHi(Type) func##Type
void funcA(void){ printf("Hi A\n"); } void funcB(void){ printf("Hi B\n"); } void funcC(void){ printf("Hi C\n"); }
int main(void) { sayHi(B)(); // Hi B return 0; }
|
Designated Initializers
初始化 array 的值可以使用
1 2 3 4
| int a[6] = { [4] = 29, [2] = 15 };
// 等於 int a[6] = { 0, 0, 15, 0, 29, 0 };
|
也可以用 ...
代表一個範圍
1
| int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
|
其他用法
1 2
| int whitespace[256] = { ['A'] = 1, ['B'] = 1, ['\h'] = 1, ['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };
|